/*
 * devices.c 
 * ADT representing i/o devices and the system timer
 *
 * Author: Tarl Hahn
 * Version: 1.0
 * 
 */

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "global.h"
#include "devices.h"

// prototypes 
int run(DevicePtr this, int microseconds, SharedMemPtr mem);
int devDestruct(DevicePtr this);

int timer_on = 0;

// Construct a device of the specified type
DevicePtr deviceConstruct(int did, int type)
{
	DevicePtr dev = (DevicePtr) malloc(sizeof(Device));
	dev->did = did;
	dev->type = type;
	dev->pid = NO_PROCESS;
	
	pthread_mutex_init(&dev->lock , NULL);
	
	// member functions
	dev->requestService = run;
	dev->destruct = devDestruct;
	return dev;
}

// destructs the device
int devDestruct(DevicePtr this)
{
	if(this == (DevicePtr) NULL) {return NULL_PTR;}
	free(this);
	return NO_ERROR;
}

// Timer thread function
void* timerRun(void* args) 
{
	DevicePtr dev = (DevicePtr) args;
	
	//printf("Timer %d: service requested\n", dev->did);
	dev->mem->run_flag = 1;
	while(dev->mem->run_flag) 
	{
		usleep(dev->time);
		dev->mem->setTimer(dev->mem, TIMER_INTERRUPT, &dev->lock);
		 //printf("Timer %d: interrupt sent\n", dev->did);
	}
	pthread_exit(0);
	
}

// Device thread function 
void* deviceRun(void* args)
{	
	DevicePtr dev = (DevicePtr) args;
	
	printf("Device %d: %d service requested\n", dev->did, dev->type);
	usleep(rand()% 10); 											// sleep
	dev->mem->addInterrupt(dev->mem, dev->pid, dev->type, &dev->lock);	// add interrupt
	dev->pid = NO_PROCESS;										// set dev owner
	
	printf("Device %d: service finished\n", dev->did);
	
}

// UI thread function  KEYBOARD and MOUSE
void* UIRun(void* args)
{	// set up thread
	DevicePtr dev = (DevicePtr) args;
	int i = 0;
	//printf("UI %d: service requested\n", dev->did);
	while(i < 10)
	{   // if getchar returns EOF sleep for 1/10 the time alloted
		if (getchar() != EOF) { break; }
		usleep(dev->time/10);
	}
	/*
	 *signal Parent thread
	 */
	 dev->pid = NO_PROCESS;
	//printf("UI %d: service finished\n", dev->did);
}

// run Device Service for the time specified and notify manager when the service is completed.
int run(DevicePtr this, int microseconds, SharedMemPtr mem)
{
	// 
	this->time = microseconds; // Time 
	this->mem =  mem;
	switch(this->type)
	{
		case TIMER:
			pthread_create(&this->device_thread, NULL, timerRun, this); // runs thread for Timer
			break;
		
		default:
			pthread_create(&this->device_thread, NULL, deviceRun, this); // runs thread for devices
	}
	
	return NO_ERROR;
}

/*
int main() 
{
	int error = 0;
	DevicePtr dev_array[4]; 
	SharedMemPtr mem = SharedMemConstruct();
	dev_array[0] = deviceConstruct(0, TIMER);
	dev_array[1] = deviceConstruct(1, NETWORK);
	dev_array[2] = deviceConstruct(2, VIDEO);
	dev_array[3] = deviceConstruct(3, KEYBOARD);
	
	int i;
	for(i = 0; i < 4; i++)
	{
		dev_array[i]->requestService(dev_array[i], i * 1000, mem);
	}
	
	pthread_join(dev_array[1]->device_thread, NULL);
	pthread_join(dev_array[2]->device_thread, NULL);
	pthread_join(dev_array[3]->device_thread, NULL);
	
	printf(mem->toStringInt(mem, &error));
}
*/
